package progetto.socialnetwork;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;


import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

public class Dati implements Serializable {
	private static final long serialVersionUID = 1L;
	private HashSet<Long> nodi;
	private HashMap<Long, HashSet<Long>> archiInUscita;
	private HashMap<Long, HashSet<Long>> archiInEntrata;

	public Dati() {
		nodi = new HashSet<Long>();
		archiInEntrata = new HashMap<Long, HashSet<Long>>();
		archiInUscita = new HashMap<Long, HashSet<Long>>();
	}

	public HashSet<Long> getNodi() {
		return nodi;
	}

	public HashMap<Long, HashSet<Long>> getArchiInUscita() {
		return archiInUscita;
	}

	public HashMap<Long, HashSet<Long>> getArchiInEntrata() {
		return archiInEntrata;
	}

	public void carica() {
		JFileChooser jfc = new JFileChooser();
		jfc.setApproveButtonText("Carica dati");
		jfc.setDialogTitle("Apri");
		int res = jfc.showOpenDialog(null);
		if (res != JFileChooser.APPROVE_OPTION) {
			return;
		}
		FileInputStream fileInputStream = null;
		ObjectInputStream objectInputStream = null;
		Dati d = null;
		try {
			fileInputStream = new FileInputStream(jfc.getSelectedFile());
			objectInputStream = new ObjectInputStream(fileInputStream);
			d = (Dati) objectInputStream.readObject();
			objectInputStream.close();
			fileInputStream.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		nodi = d.nodi;
		archiInEntrata = d.archiInEntrata;
		archiInUscita = d.archiInUscita;
		System.out.println("Dati caricati correttamente");
	}

	public void salva() {
		FileOutputStream fileOutputStream = null;
		ObjectOutputStream objectOutputStream = null;
		try {
			JFileChooser jfc = new JFileChooser();
			jfc.setApproveButtonText("Salva dati");
			jfc.setDialogTitle("Salva");
			int res = jfc.showOpenDialog(null);
			if (res != JFileChooser.APPROVE_OPTION) {
				System.out.println("Salvataggio annullato");
				return;
			}
			File f = jfc.getSelectedFile();
			if (f.exists()) {
				res = JOptionPane.showConfirmDialog(null,
						"File esistente, vuoi sovrascrivere i dati? ",
						"File esistente", JOptionPane.YES_NO_OPTION);
				if (res != JOptionPane.YES_OPTION) {
					System.out.println("Salvataggio annullato");
					return;
				}
			}
			fileOutputStream = new FileOutputStream(f);
			objectOutputStream = new ObjectOutputStream(fileOutputStream);
			objectOutputStream.writeObject(this);
			objectOutputStream.close();
			fileOutputStream.close();
			System.out.println("Dati salvati correttamente nel file "
					+ jfc.getSelectedFile());
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	public void inserisciNodo(long nodo) {
		nodi.add(nodo);
	}

	public boolean NodoVisitato(long nodo) {
		return nodi.contains(nodo);
	}

	/** Restituisce il numero di following di un nodo */
	public int archiInUscita(long nodo) {
		if (!archiInUscita.containsKey(nodo))
			return 0;
		return archiInUscita.get(nodo).size();
	}
	
	/** Restituisce il numero di followers di un nodo */
	public int archiInEntrata(long nodo) {
		if (!archiInEntrata.containsKey(nodo))
			return 0;
		return archiInEntrata.get(nodo).size();
	}

	public void aggiungiFollowers(long nodo, long[] followers) {
		nodi.add(nodo);
		for (int i = 0; i < followers.length; i++) {
			nodi.add(followers[i]);
		}
		if (archiInEntrata.containsKey(nodo)) {
			HashSet<Long> set = archiInEntrata.get(nodo);
			for (int i = 0; i < followers.length; i++) {
				set.add(followers[i]);
			}
		} else {
			HashSet<Long> set = new HashSet<Long>();
			for (int i = 0; i < followers.length; i++) {
				set.add(followers[i]);
			}
			archiInEntrata.put(nodo, set);
		}

		for (int i = 0; i < followers.length; i++) {
			long foll = followers[i];
			if (archiInUscita.containsKey(foll)) {
				HashSet<Long> set = archiInUscita.get(foll);
				set.add(nodo);
			} else {
				HashSet<Long> set = new HashSet<Long>();
				set.add(nodo);
				archiInUscita.put(foll, set);
			}
		}
	}

	public void aggiungiFollowing(long nodo, long[] following) {
		nodi.add(nodo);
		for (int i = 0; i < following.length; i++) {
			nodi.add(following[i]);
		}
		if (archiInUscita.containsKey(nodo)) {
			HashSet<Long> set = archiInUscita.get(nodo);
			for (int i = 0; i < following.length; i++) {
				set.add(following[i]);
			}
		} else {
			HashSet<Long> set = new HashSet<Long>();
			for (int i = 0; i < following.length; i++) {
				set.add(following[i]);
			}
			archiInUscita.put(nodo, set);
		}

		for (int i = 0; i < following.length; i++) {
			long foll = following[i];
			if (archiInEntrata.containsKey(foll)) {
				HashSet<Long> set = archiInEntrata.get(foll);
				set.add(nodo);
			} else {
				HashSet<Long> set = new HashSet<Long>();
				set.add(nodo);
				archiInEntrata.put(foll, set);
			}
		}
	}

	public void merge(Dati nuovi) {
		nodi.addAll(nuovi.nodi);
		
		// archi in entrata
		Iterator<Long> it = nuovi.archiInEntrata.keySet().iterator();
		while (it.hasNext()) {
			long corr = it.next();
			HashSet<Long> archi = nuovi.archiInEntrata.get(corr);
			if (archiInEntrata.containsKey(corr)) {
				archiInEntrata.get(corr).addAll(archi);
			} else {
				archiInEntrata.put(corr, archi);
			}
		}
		
		// archi in uscita
		it = nuovi.archiInUscita.keySet().iterator();
		while (it.hasNext()) {
			long corr = it.next();
			HashSet<Long> archi = nuovi.archiInUscita.get(corr);
			if (archiInUscita.containsKey(corr)) {
				archiInUscita.get(corr).addAll(archi);
			} else {
				archiInUscita.put(corr, archi);
			}
		}

	}

	public void stampaDati(boolean stampaNodi, boolean stampaArchiInEntrata,
			boolean stampaArchiInUscita) {
		if (stampaNodi) {
			System.out.println("Nodi visitati: ");
			Iterator<Long> it = nodi.iterator();
			while (it.hasNext()) {
				System.out.print(it.next() + "; ");
			}
			System.out.println();
			System.out.println("----");
		}
		Iterator<Long> itKeysIterator = archiInEntrata.keySet().iterator();
		Iterator<Long> itValuesIterator = null;

		if (stampaArchiInEntrata) {
			System.out.println("ARCHI IN ENTRATA: ");
			while (itKeysIterator.hasNext()) {
				long corr = itKeysIterator.next();
				itValuesIterator = archiInEntrata.get(corr).iterator();
				System.out.print("Chiave: " + corr);
				System.out.print(" - Valori: ");
				while (itValuesIterator.hasNext()) {
					System.out.print(itValuesIterator.next() + "; ");
				}
				System.out.println();
			}

			System.out.println();
			System.out.println("----");
		}
		if (stampaArchiInUscita) {
			System.out.println("ARCHI IN USCITA: ");
			itKeysIterator = archiInUscita.keySet().iterator();
			while (itKeysIterator.hasNext()) {
				long corr = itKeysIterator.next();
				itValuesIterator = archiInUscita.get(corr).iterator();
				System.out.print("Chiave: " + corr);
				System.out.print(" - Valori: ");
				while (itValuesIterator.hasNext()) {
					System.out.print(itValuesIterator.next() + "; ");
				}
				System.out.println();
			}
		}
	}

	public void stampaSize() {
		System.out.println("Nodi " + numNodi());
		System.out.println("Keys entrata " + numArchiInEntrataKeys());
		System.out.println("Values entrata " + numArchiInEntrataValues());
		System.out.println("Keys uscita " + numArchiInUscitaKeys());
		System.out.println("Values uscita " + numArchiInUscitaValues());
		System.out.println("------");
	}

	public int numNodi() {
		return nodi.size();
	}

	public int numArchiInEntrataKeys() {
		return archiInEntrata.keySet().size();
	}

	public int numArchiInEntrataValues() {
		int tot = 0;
		Iterator<Long> keys = archiInEntrata.keySet().iterator();
		while (keys.hasNext()) {
			tot += archiInEntrata.get(keys.next()).size();
		}
		return tot;
	}

	public int numArchiInUscitaKeys() {
		return archiInUscita.keySet().size();
	}

	public int numArchiInUscitaValues() {
		int tot = 0;
		Iterator<Long> keys = archiInUscita.keySet().iterator();
		while (keys.hasNext()) {
			tot += archiInUscita.get(keys.next()).size();
		}
		return tot;
	}
	
}
